﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Collections.Concurrent;
using System.Threading;
using System.Diagnostics;
using YiNing.UI.Tools;
using static YiNing.UI.Config.Enums;
using YiNing.UI.Forms;

namespace YiNing.UI.Controls
{
    public partial class NonstandardWafermap : UserControl
    {
        /// <summary>
        /// 
        /// </summary>

        /// <summary>
        /// 手动添加一片区域 
        /// </summary>
        /// <param name="leftTopP">左上角机械坐标</param>
        /// <param name="rightBottomP">右下角机械坐标</param>
        /// <param name="dieWidth">芯片机械宽</param>
        /// <param name="dieHeight">芯片机械高</param>
        /// <param name="xDieNum">x方向芯片个数</param>
        /// <param name="yDieNum">y方向芯片个数</param>
        public bool AddDiesByRect(Point waferCenter, Point leftTopP, Point rightBottomP, double waferRadius, double dieWidth, double dieHeight, int xDieNum, int yDieNum)
        {
            if (waferRobotgQuadTree == null) return false;
            Quad quad = new Quad(leftTopP.X, rightBottomP.Y, rightBottomP.X, leftTopP.Y);
            List<Die> res = new List<Die>();
            waferRobotgQuadTree.SearchArea(ref quad, ref res);
            if (res.Count > 0) { DarkMessageBox.ShowWarning("选择的区域有重叠请重新选择"); return false; }
            if (WaferMaxX == 0 || WaferMaxY == 0 || WaferMinX == 0 || WaferMinY == 0) { DarkMessageBox.ShowWarning("请先设置晶圆的区域WaferMinX, WaferMaxX, WaferMinY, WaferMaxY"); return false; }
            if (dataset == null) dataset = new List<Die>();
            double rectWidth = rightBottomP.X - leftTopP.X;
            double rectHeight = leftTopP.Y - rightBottomP.Y;
            double intervalX = rectWidth / xDieNum;
            double intervalY = rectHeight / yDieNum;

            double firstDieCenterX = leftTopP.X + dieWidth / 2;
            double firstDieCenterY = leftTopP.Y - dieHeight / 2;

            for (int y = 0; y < yDieNum; y++)
            {
                for (int x = 0; x < xDieNum; x++)
                {
                    int xPulse = Convert.ToInt32(firstDieCenterX + intervalX * x);
                    int yPulse = Convert.ToInt32(firstDieCenterY - intervalY * y);
                    Die tempDie = new Die()
                    {
                        ColorIndex = Die.DefaultUndo,
                        Enabled = true,
                        IsEdge = false,
                        OffsetWaferCenterXPulse = xPulse - waferCenter.X,
                        OffsetWaferCenterYPulse = yPulse - waferCenter.Y,
                        WaferCenterXPulse = waferCenter.X,
                        WaferCenterYPulse = waferCenter.Y,
                        WaferRadius = waferRadius,
                        XIndex = x,
                        YIndex = y,
                        XPluse = xPulse,
                        YPluse = yPulse,
                    };
                    tempDie.DieQuad = new Quad
                                 (tempDie.GetDieRectLeftBottomPoint(true, 1, 1, dieWidth, dieHeight).X,
                                 tempDie.GetDieRectLeftBottomPoint(true, 1, 1, dieWidth, dieHeight).Y,
                                 tempDie.GetDieRectRightTopPoint(true, 1, 1, dieWidth, dieHeight).X,
                                 tempDie.GetDieRectRightTopPoint(true, 1, 1, dieWidth, dieHeight).Y);
                    dataset.Add(tempDie);
                }
            }
            Invalidate();
            return true;
        }
        /// <summary>
        /// Die鼠标点击事件
        /// </summary>
        public event EventHandler<Die> OnDieClick; //定义一个委托类型的事件
        public event EventHandler<Die[,]> OnMappingUpdate; //定义一个委托类型的事件 
        private String tooSmallString = "TOO SMALL";
        private int _DieAlpha = 150;
        public String TooSmallString
        {
            get { return tooSmallString; }
            set { tooSmallString = value; }
        }

        private String noDataString = "NO DATA";

        [Description("芯片的透明度")]
        [DefaultValue(150)]
        public int DieAlpha
        {
            get { return _DieAlpha; }
            set
            {
                _DieAlpha = value;
                Invalidate();
            }
        }

        public String NoDataString
        {
            get { return noDataString; }
            set { noDataString = value; }
        }


        private Quad _waferMappingQuad, _waferRobotQuad;
        private QuadTree<Die> waferMappingQuadTree;
        private QuadTree<Die> waferRobotgQuadTree;
        private double _scaleX = 0.2;
        private double _scaleY = 0.2;
        private Point _waferCenter;
        private double _waferRadius;
        private double _minX;
        private double _minY;
        private double _maxX;
        private double _maxY;
        private double baseWidth;
        private double baseHeight;



        private int _SelectX = 0, _SelectY = 0;
        private Die _SelectOneDie;
        private List<Die> _SelectDies;
        private Die[] _SelectRegionDiagonalDie;
        private Die _selectStartDie, _selectEndDie; // 这两个是多选die的开始和结束die
        private bool SelectMode = false; //是否是选中模式,鼠标up就为false
        private bool _SelectMultiple = true; //是否是选中模式,鼠标up就为false
        private bool _RemoveIncompleteDie = false; //去除边沿不完整的die
        private int _ExcludeEdgeNum = 0; //边沿排除个数
        private List<Die> dataset;
        private bool _DirectionOnlyNgDie = false;

        private int _DieIntervalX = 0;
        private int _DieIntervalY = 0;

        private int _DieAllNum = 0;
        private int _DieOkNum = 0;
        private int _DieNgNum = 0;

        private TraitType _NotcheOrFlat = TraitType.Notch;

        /// <summary>
        /// 类型
        /// </summary>
        public TraitType NotcheOrFlat
        {
            get { return _NotcheOrFlat; }
            set { _NotcheOrFlat = value; }
        }

        /// <summary>
        /// 晶圆的Quad区域
        /// </summary>
        public double WaferMinX
        {
            get { return _minX; }
        }
        public double WaferMinY
        {
            get { return _minY; }
        }
        public double WaferMaxX
        {
            get { return _maxX; }
        }
        public double WaferMaxY
        {
            get { return _maxY; }
        }

        /// <summary>
        /// 晶元中心
        /// </summary>
        public Point WaferCenter
        {
            get { return _waferCenter; }
        }
        /// <summary>
        /// 晶圆半径
        /// </summary>
        public double WaferRadius
        {
            get { return _waferRadius; }
        }



        /// <summary>
        /// 缩放x
        /// </summary>
        public double ScaleX
        {
            get { return _scaleX; }
            set { _scaleX = value; }
        }
        /// <summary>
        /// 缩放y
        /// </summary>
        public double ScaleY
        {
            get { return _scaleY; }
            set { _scaleY = value; }
        }

        /// <summary>
        /// 所有芯片总个数
        /// </summary>
        public int DieAllNum
        {
            get { return _DieAllNum; }
            set { _DieAllNum = value; }
        }

        /// <summary>
        /// 良品芯片总个数
        /// </summary>
        public int DieOkNum
        {
            get { return _DieOkNum; }
            set { _DieOkNum = value; }
        }

        /// <summary>
        /// 缺陷芯片总个数
        /// </summary>
        public int DieNgNum
        {
            get { return _DieNgNum; }
            set { _DieNgNum = value; }
        }

        [Description("获取X方向上的间距")]
        public int DieIntervalX
        {
            get { return _DieIntervalX; }
        }
        [Description("获取Y方向上的间距")]
        public int DieIntervalY
        {
            get { return _DieIntervalY; }
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000; // 用双缓冲绘制窗口的所有子控件
                return cp;
            }
        }
        /// <summary>
        /// 是否多选
        /// </summary>
        [Description("箭头操作只对NG芯片有效")]
        [DefaultValue(false)]
        public bool DirectionOnlyNgDie
        {
            get { return _DirectionOnlyNgDie; }
            set
            {
                _DirectionOnlyNgDie = value;
            }
        }
        /// <summary>
        /// 是否多选
        /// </summary>
        [Description("是否多选")]
        [DefaultValue(true)]
        public bool SelectMultiple
        {
            get { return _SelectMultiple; }
            set
            {
                _SelectMultiple = value;
            }
        }

        [Description("边沿排除的个数")]
        [DefaultValue(0)]
        public int ExcludeEdgeNum
        {
            get { return _ExcludeEdgeNum; }
            set
            {
                _ExcludeEdgeNum = value;

                //for (int x = 0; x < dataset.GetLength(0); x++)
                //{
                //    for (int y = 0; y < dataset.GetLength(1); y++)
                //    {
                //        dataset[x, y].IsEdge = false;
                //        dataset[x, y].Enabled = false;
                //    }
                //}

                Invalidate();
            }
        }

        [Description("是否去除不完整的区域")]
        [DefaultValue(false)]
        public bool RemoveIncompleteDie
        {
            get { return _RemoveIncompleteDie; }
            set
            {
                _RemoveIncompleteDie = value;
                Invalidate();
            }
        }

        [Description("数据")]
        public List<Die> Dataset
        {
            get { return dataset; }
            set
            {
                //if (value == null) return;
                //这个缩放是以当前的框高来了，其实应该是以boundbox的宽高
                if (value != null && (WaferMaxX == 0 || WaferMaxY == 0 || WaferMinX == 0 || WaferMinY == 0)) { DarkMessageBox.ShowWarning("请先设置晶圆的区域WaferMinX, WaferMaxX, WaferMinY, WaferMaxY"); return; }
                baseWidth = Width;
                baseHeight = Height;
                _DieIntervalX = 0;
                _DieIntervalY = 0;
                dataset = null;
                GC.Collect();
                SelectOneDie = null;
                if (value != null)
                {
                    foreach (var one in value)
                    {
                        one.WaferCenterXPulse = WaferCenter.X;
                        one.WaferCenterYPulse = WaferCenter.Y;
                        one.WaferRadius = WaferRadius;
                        one.XPluse = WaferCenter.X + one.OffsetWaferCenterXPulse;
                        one.YIndex = WaferCenter.Y + one.OffsetWaferCenterYPulse;
                    }
                }
                dataset = value;
                Invalidate();
            }
        }

      
        /// <summary>
        /// 选中单个die
        /// </summary>
        [Description("选中单个die")]
        public Die SelectOneDie
        {
            get { return _SelectOneDie; }
            set
            {
                _SelectOneDie = value;
                MouseDownDie(_SelectOneDie);
            }
        }

        /// <summary>
        /// 多选区域的对角线2点，会自动计算该点属于区域的那个顶点,Get获取的可能就不是最终传入的两个点，最终保存的是左上角点和右下角点
        /// </summary>
        [Description("多选区域的对角线2点，会自动计算该点属于区域的那个顶点,Get获取的可能就不是最终传入的两个点，最终保存的是左上角点和右下角点")]
        public Die[] SelectRegionDiagonalDie
        {
            get { return _SelectRegionDiagonalDie; }
            set
            {
                if (value != null && value.Length >= 2)
                {
                    _selectStartDie = value[0];
                    _selectEndDie = value[1];
                    DrawSelectDies();
                }
            }
        }

        /// <summary>
        /// 获取多选中的die的列表，暂时设置为只读，如果要动态改变的话，只用设置左上角的点和右下角的点即可
        /// </summary>
        //[Description("获取多选中的die的列表，暂时设置为只读，如果要动态改变的话，只用设置左上角的点和右下角的点即可")]
        private List<Die> SelectDies
        {
            get { return _SelectDies; }
        }

        private int translation_x=0;

        public int TranslationX
        {
            get { return translation_x; }
            set { translation_x = value; }
        }

        private int translation_y=0;

        public int TranslationY
        {
            get { return translation_y; }
            set { translation_y = value; }
        }

        private int rotation;

        /// <summary>
        /// 旋转角度可能会有问题，未测试
        /// </summary>
        [Description("旋转角度可能会有问题，未测试")]
        public int Rotation
        {
            get { return rotation; }
            set { if (value % 90 == 0 && value >= 0 && value < 360)
                    rotation = value;
                else
                    throw new ArgumentException("Rotation has to be 0, 90, 180 or 270 degrees (Is "+value+")");
                Invalidate();
            }
        }
        
        
        private float zoom;

        public float Zoom
        {
            get { return zoom; }
            set { zoom = value; Invalidate(); }
        }
        private int notchLocation = 0;


        /// <summary>
        /// 缺角位置
        /// </summary>
        [Description("缺角位置")]
        public int Notchlocation
        {
            get { return notchLocation; }
            set {
                if (value % 90 == 0 && value >= 0 && value <= 270)
                    notchLocation = value;
                else
                    throw new ArgumentException("NotchLocation has to be 0, 90, 180 or 270 degrees (Is "+value+")");
                }
        }

        public int tempX = -1, tempY = -1;
        private DarkLabel darkLabel1;
        private DarkSectionPanel darkSettionPanel;
        private DarkLabel darkLabel2;
        private DarkLabel darkLabel4;
        private DarkLabel darkLabel3;
        private Color[] colors;
        private DarkLabel lbBoundboxInfo;
        private DarkLabel lbMouseDown;
        private DarkLabel lbWaferCenter;
        private ToolTip toolTip1;
        private IContainer components;

        /// <summary>
        /// 所有颜色
        /// </summary>
        [Description("所有颜色")]
        public Color[] Colors
        {
            get { return colors; }
            set { colors = value; }
        }

        private bool interactive = true;
        /// <summary>
        /// 是否可交互
        /// </summary>
        [Description("是否可交互")]
        [DefaultValue(true)]
        public bool Interactive
        {
            get { return interactive; }
            set
            {
                interactive = value;
                registerEvents();
            }
        }


        public NonstandardWafermap()
        {
            baseWidth = Width;
            baseHeight = Height;
            zoom =1f;
            InitializeComponent();
            SetStyle(ControlStyles.ResizeRedraw, true);
            DoubleBuffered = true;
            if (!IsDesignMode())
            {
                setupDefaultColors();
                registerEvents();
            }
            this.Resize += NonstandardWafermap_Resize;
        }

        /// <summary>
        /// 设置晶圆的信息
        /// </summary>
        /// <param name="wCenter"></param>
        /// <param name="wRadius"></param>
        public void SetWaferInfo(Point wCenter, double wRadius)
        {
            _waferCenter = wCenter;
            _waferRadius = wRadius;
            _minX = WaferCenter.X - WaferRadius;
            _maxX = WaferCenter.X + WaferRadius;
            _minY = WaferCenter.Y - WaferRadius;
            _maxY = WaferCenter.Y + WaferRadius;
        }

        private void NonstandardWafermap_Resize(object sender, EventArgs e)
        {
            ScaleX *= Width / baseWidth;
            ScaleY *= Height / baseHeight;
        }

        public bool IsDesignMode()
        {
            bool returnFlag = false;

#if DEBUG
            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                returnFlag = true;
            }
            else if (Process.GetCurrentProcess().ProcessName == "devenv")
            {
                returnFlag = true;
            }
#endif

            return returnFlag;
        }

        public void ReFresh()
        {
            Invalidate();
        }
       

        private void setupDefaultColors()
        {
            // Just some sample colors to get started
            colors = new Color[255];
            colors[0] = Color.FromArgb(_DieAlpha, Color.Green);
            colors[1] = Color.FromArgb(_DieAlpha, Color.Red);
            colors[2] = Color.FromArgb(_DieAlpha, Color.Yellow);
            colors[3] = Color.FromArgb(_DieAlpha, Color.Blue);
            colors[4] = Color.FromArgb(_DieAlpha, Color.Orange);
            colors[5] = Color.FromArgb(_DieAlpha, Color.Magenta);
            colors[6] = Color.FromArgb(_DieAlpha, Color.DarkBlue);
            colors[7] = Color.FromArgb(_DieAlpha, Color.Pink);
            colors[50] = Color.FromArgb(_DieAlpha, Color.Black);
        }

        private void Wafermap_Load(object sender, EventArgs e)
        {
            this.Dock = DockStyle.Fill;
        }

        private bool isScaled;

        public bool IsScaled
        {
            get { return isScaled; }
            
        }

        private int scaleFactor;

        public int ScaleFactor
        {
            get { return scaleFactor; }
        }
        
        
        // We need some globals to be available for calculations
        RectangleF boundingBox_;
        SizeF dieSize_;
        

        protected override void OnPaint(PaintEventArgs e)
        {
            // set rotation
            e.Graphics.RotateTransform((float)rotation);
            if(rotation!=0)
            {
                // When we rotate, we also have to translate
                switch (rotation)
                {
                    case 90:
                        e.Graphics.TranslateTransform(0, -boundingBox_.Width);
                        break;
                    case 180:
                        e.Graphics.TranslateTransform(-boundingBox_.Width,-boundingBox_.Height);
                        break;
                    case 270:
                        e.Graphics.TranslateTransform(-boundingBox_.Height, 0);
                        break;
                }
            }
            // set additional translation
            e.Graphics.TranslateTransform(translation_x, translation_y); 

            // 使用抗锯齿
            e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
            
            // Here comes everything that has to be calculated on each resize/redraw
            // Just do this calculations once
            // Let's find the best Size for the outline
            float w = this.Width*zoom;
            float h = this.Height*zoom;
           
            float size = w < h ? w : h;
            // Wafersize is size-2 because we're not drawing the first and the last pixels
            SizeF wafersize = new SizeF(size - 2, size - 2);
            PointF starting = new PointF((w - size) / 2f, (h - size) / 2f);
            RectangleF boundingBox = new RectangleF(starting, wafersize);
            boundingBox_ = boundingBox;

            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox);


            double robotWidth = WaferMaxX - WaferMinX;
            double robotHeight = WaferMaxY - WaferMinY;
            robotWidth = robotWidth == 0 ? Width : robotWidth;
            robotHeight = robotHeight == 0 ? Height : robotHeight;
            ScaleX = boundingBox.Width / robotWidth;
            ScaleY = boundingBox.Height / robotHeight;

            _waferMappingQuad = new Quad(0, 0, Width, Height);
            _waferRobotQuad = new Quad(WaferMinX, WaferMinY, WaferMaxX, WaferMaxY);

            waferMappingQuadTree = new QuadTree<Die>(20, 8, ref _waferMappingQuad);
            waferRobotgQuadTree = new QuadTree<Die>(20, 8, ref _waferRobotQuad);
            ////// Set clipping region to path.
            //e.Graphics.SetClip(clipPath, CombineMode.Replace);
            ////clipPath = new GraphicsPath();
            ////clipPath.AddRectangle(new RectangleF(new PointF(boundingBox.Left, boundingBox.Bottom -10), new SizeF(boundingBox.Width, boundingBox.Height)));
            ////e.Graphics.SetClip(clipPath, CombineMode.Exclude);
            ////drawCircle(e.Graphics, boundingBox);

            // Let's calculate everything needed for drawing the dies
            if (dataset != null && dataset.Count > 0)
            {
                drawCircle(e.Graphics, boundingBox);
                //e.Graphics.FillEllipse(new SolidBrush(Color.Red), new RectangleF(boundingBox.X + boundingBox.Width /2, boundingBox.Y + boundingBox.Height / 2, 10, 10));
                drawDies(e.Graphics, boundingBox, dataset, _SelectDies);
            }
            else
            {
                drawCircle(e.Graphics, boundingBox);
                // Display "No Data" message
                FontFamily myFontFamily = new FontFamily("宋体");
                Font myFont = new Font(myFontFamily,
                   10,
                   FontStyle.Bold);

                e.Graphics.DrawString(noDataString, myFont, new SolidBrush(Color.DimGray), new PointF(w / 2 - 25, h / 2));
            }
            drawNotch(e.Graphics, boundingBox, notchLocation);
            //e.Graphics.ScaleTransform(2, 2);
        }

        // Try to reuse - only instantiated once
        SolidBrush waferFillbrush = new SolidBrush(Color.DimGray);
        Pen blackPen = new Pen(Color.Black);
        //底部的缺口
        SolidBrush notchFillBrush = new SolidBrush(Color.FromArgb(255, Color.White));
        /// <summary>
        /// 绘画园
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        private void drawCircle(Graphics g, RectangleF boundingBox)
        {
            //g.FillPie(Brushes.Pink, new Rectangle(-10, 20, this.Width, this.Height), 180, 180);//绘制半圆
            g.FillEllipse(waferFillbrush, boundingBox);
            //g.DrawEllipse(blackPen, boundingBox);
        }

        /// <summary>
        /// 绘画底部的缺口
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        /// <param name="location"></param>
        private void drawNotch(Graphics g, RectangleF boundingBox, int location)
        {
            try
            {
                /*
                            *  //在晶圆上画凹口（物理性质）以对准。可以是0、90、180、270度
                               //从0开始° 底部（逆时针）
                               //形状固定在切割圆上
                            */
                float size = boundingBox.Width < boundingBox.Height ? boundingBox.Width : boundingBox.Height;
                size = size * 0.05f;
                // 计算切口的位置
                // 180°
                float x = boundingBox.X + (boundingBox.Width / 2f) - (size / 2f);
                float y = boundingBox.Y - (size / 2f);
                int start = 0;
                int end = 180;
                switch (location)
                {
                    case 0:
                        y = boundingBox.Y + boundingBox.Height - (size / 2f);
                        end = -180;
                        if(NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(Color.FromArgb(255, this.BackColor));
                            g.FillRectangle(notchFillBrush, 0, y, Width, size);
                        }
                        break;
                    case 90:
                        x = boundingBox.X - (size / 2f);
                        y = boundingBox.Y + (boundingBox.Height / 2f) - (size / 2f);
                        start = 90;
                        end = -180;
                        if (NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(Color.FromArgb(255, this.BackColor));
                            g.FillRectangle(notchFillBrush, x, 0, size, Height);
                        }
                        break;
                    case 270:
                        x = boundingBox.X + boundingBox.Width - (size / 2f);
                        y = boundingBox.Y + (boundingBox.Height / 2f) - (size / 2f);
                        start = 90;
                        end = 180;
                        if (NotcheOrFlat == TraitType.Flat)
                        {
                            notchFillBrush = new SolidBrush(Color.FromArgb(255, this.BackColor));
                            g.FillRectangle(notchFillBrush, x, 0, size, Height);
                        }
                        break;
                }

                if(NotcheOrFlat == TraitType.Notch)
                {
                    g.FillPie(notchFillBrush, x, y, size, size, start, end);
                }
            }
            catch(Exception er)
            {

            }
        }
        Pen dieOutlinePen = new Pen(Color.White, 0.1f);

        /// <summary>
        /// 转换坐标为左下角点
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        private Point TransToLeftBottom(Point pt)
        {
            return new Point(pt.X, Height - pt.Y);
        }
        /// <summary>
        /// 绘画单个die的样式和选中的die样式
        /// </summary>
        /// <param name="g"></param>
        /// <param name="boundingBox"></param>
        /// <param name="data"></param>
        /// <param name="selectDies"></param>
        /// <param name="dieSize"></param>
        private void drawDies(Graphics g, RectangleF boundingBox, List<Die> data, List<Die> selectDies)
        {
            lbWaferCenter.Text = string.Format("WaferCenter: x={0}, y={1}", boundingBox.X + boundingBox.Width / 2, boundingBox.Y + boundingBox.Height / 2);
            lbBoundboxInfo.Text = string.Format("BoundboxInfo: x={0}, y={1}, w={2}, h={3}", boundingBox.X, boundingBox.Y, boundingBox.Width, boundingBox.Height);
            //g.TranslateTransform(0, -boundingBox.Y);
            if (!IsHandleCreated) return;
            if (colors == null) colors = Die.DefaultColors;
            //g.DrawRectangle(dieOutlinePen, boundingBox.X + 100, boundingBox.Y + 100, 50, 50);
            foreach (var oneDie in data)
            {
                waferRobotgQuadTree.Insert(oneDie, ref oneDie.DieQuad);
                Point point = TransToLeftBottom(oneDie.GetDieRectLeftTopPoint(true, ScaleX, ScaleY));
                point = new Point(point.X + Convert.ToInt32(boundingBox.X), point.Y - Convert.ToInt32(boundingBox.Y));
                Color fill = Color.FromArgb(_DieAlpha, colors[oneDie.ColorIndex]);
                Size tempSize = oneDie.GetDieSize(ScaleX, ScaleY);
                RectangleF die = new RectangleF(point, new Size(tempSize.Width - 2, tempSize.Height - 1));
                g.FillRectangle(new SolidBrush(fill), die);
                //g.DrawRectangle(dieOutlinePen, die.X, die.Y, die.Width - 1, die.Height - 1);
                var aaa = new List<Die>();
                if (!waferMappingQuadTree.FindCollisions(oneDie, ref aaa))
                {
                    waferMappingQuadTree.Insert(oneDie, new Quad(die.Left, Height - die.Bottom, die.Right, Height - die.Top));
                }
            }
            //dataset = data;
            //if (savePath != "")
            //{
            //    string aa = JsonConvert.SerializeObject(visibleDataset);
            //    File.WriteAllText(savePath, aa);
            //    VisibleDatasetSavePath = "";
            //}
            #region 绘画选中die的样式
            if (selectDies != null) // 多个die
            {
                Die[] dies = GetLeftTopAndRightBottomDie(_selectStartDie, _selectEndDie);
                PointF positionSelect = new PointF(boundingBox_.X + (float)dies[0].XIndex * dieSize_.Width - 1, boundingBox_.Y + (float)dies[0].YIndex * dieSize_.Height - 1);
                RectangleF dieSelect = new RectangleF(positionSelect, new SizeF((dies[1].XIndex - dies[0].XIndex + 1) * dieSize_.Width + 2, (dies[1].YIndex - dies[0].YIndex + 1) * dieSize_.Height + 2));

                ////四个边角只要右一个不在里面就直接返回不绘制
                //if (!g.IsVisible(positionSelect.X, positionSelect.Y) || !g.IsVisible(positionSelect.X, positionSelect.Y + dieSize.Height) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y) || !g.IsVisible(positionSelect.X + dieSize.Width, positionSelect.Y + dieSize.Height))
                //{
                //    return;
                //}

                g.DrawRectangle(new Pen(Color.White, 4), dieSelect.X + 2, dieSelect.Y + 2, dieSelect.Width - 4, dieSelect.Height - 4);
                g.DrawRectangle(new Pen(Color.Black, 4), dieSelect.X - 2, dieSelect.Y - 2, dieSelect.Width + 4, dieSelect.Height + 4);
            }
            else if (_SelectOneDie != null && !_SelectOneDie.IsEdge) //单个die选中
            {
                // 放到for循环外主要是为了解决右边和下边的边框被重绘了造成部分白色区域
                Color fillSelect = Color.FromArgb(255, colors[_SelectOneDie.ColorIndex]);
                Point point = TransToLeftBottom(_SelectOneDie.GetDieRectLeftTopPoint(true, ScaleX, ScaleY));
                point = new Point(point.X + Convert.ToInt32(boundingBox.X) - 1, point.Y - Convert.ToInt32(boundingBox.Y) - 1);
                Size dieSize = _SelectOneDie.GetDieSize(ScaleX, ScaleY);

                RectangleF dieSelect = new RectangleF(point, new Size(dieSize.Width + 2, dieSize.Height + 2));

             
                g.FillRectangle(new SolidBrush(fillSelect), dieSelect);
                // 这里是重绘选中的芯片
                g.DrawRectangle(new Pen(Color.White, 4), dieSelect.X + 2, dieSelect.Y + 2, dieSelect.Width - 4, dieSelect.Height - 4);
                g.DrawRectangle(new Pen(Color.Black, 4), dieSelect.X - 2, dieSelect.Y - 2, dieSelect.Width + 4, dieSelect.Height + 4);
            }
            #endregion
            //Invalidate();
        }



        private void registerEvents()
        {
            this.MouseMove += Wafermap_MouseMove;
            // Event to be registered
            if (interactive)
            {
                //this.MouseClick += Wafermap_MouseClick;
                this.MouseDown += Wafermap_MouseDown;
                this.MouseUp += Wafermap_MouseUp;
   
                KeyDown += Wafermap_KeyDown;
                //darkSettionPanel.Visible = true;
            }
            else
            {
                this.MouseDown -= Wafermap_MouseDown;
                this.MouseUp -= Wafermap_MouseUp;
                //this.MouseMove -= Wafermap_MouseMove;
                KeyDown -= Wafermap_KeyDown;
                darkSettionPanel.Visible = false;
            }
        }
        
        protected override bool IsInputKey(Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Right:
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                    return true;
            }
            return base.IsInputKey(keyData);
        }

        private int id = 0;
        /// <summary>
        /// 键盘上下左右控制
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Down)
            {
                for (int i = id; i < dataset.Count; i++)
                {
                    if (dataset[i].ColorIndex == Die.DefaultUndo)
                    {
                        SelectOneDie = dataset[i];
                        id = i;
                    }
                    else continue;
                }
            }
            Invalidate();
            //if (e.KeyData == Keys.Left)
            //{
            //    //SelectX--;
            //    Invalidate();
            //    if (DirectionOnlyNgDie) MoveLineNextNgDie(false);
            //}
            //else if (e.KeyData == Keys.Right)
            //{
            //    //SelectX++;
            //    Invalidate();
            //    if (DirectionOnlyNgDie) MoveLineNextNgDie();
            //}
            //else if (e.KeyData == Keys.Up)
            //{
            //    SelectY--;
            //    Invalidate();
            //    if (DirectionOnlyNgDie) MoveLineFirstNgDie();
            //}
            //else if (e.KeyData == Keys.Down)
            //{
            //    SelectY++;
            //    Invalidate();
            //    if (DirectionOnlyNgDie) MoveLineFirstNgDie();
            //}
        }

        /// <summary>
        /// 鼠标按下事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseDown(object sender, MouseEventArgs e)
        {
            //List<Die> dies = new List<Die>();
            //waferQuadTree.SearchPoint(e.X, Height - e.Y, ref dies);
            //int aa = dies.Count;
            //// Basically the same as MouseMove, just a few other infos passed
            //float x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;
            //float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;
            //int x = (int)Math.Floor(x_coord);
            //int y = (int)Math.Floor(y_coord);
            //try
            //{
            //    if (dataset == null) return;
            //    if (_SelectDies != null) { _SelectDies.Clear(); _SelectDies = null; }
            //    if(e.Button == MouseButtons.Left)
            //    {
            //        dieMouseDown(dataset[x, y], e);
            //    }
            //    else if (e.Button == MouseButtons.Right)
            //    {
            //        dataset[x, y].ColorIndex = Die.DefaultEdge;
            //        dataset[x, y].IsEdge = false;
            //        Invalidate();
            //    }
            //    else if (e.Button == MouseButtons.Middle)
            //    {
            //        dataset[x, y].ColorIndex = Die.DefaultUndo;
            //        dataset[x, y].IsEdge = true;
            //        Invalidate();
            //    }
            //    SelectMode = true;
            //    _SelectX = x;
            //    _SelectY = y;
            //    _SelectOneDie = dataset[x, y];
            //    _selectStartDie = _SelectOneDie;
            //}
            //catch (Exception ex)
            //{
            //    System.Diagnostics.Debug.WriteLine("Not good click..");
            //    //throw ex;
            //}
        }

        private int previousX = -1, previousY = -1;
        /// <summary>
        /// 鼠标移动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseMove(object sender, MouseEventArgs e)
        {
            try
            {
                if (waferMappingQuadTree == null) return;
                List<Die> dies = new List<Die>();
                waferMappingQuadTree.SearchPoint(e.X, Height - e.Y, ref dies);
                if (dies.Count == 0) {
                    toolTip1.Hide(this);
                    return;
                };
                toolTip1.Show(string.Format("{0} {1}", dies[0].ProgramName, dies[0].Id), this, new Point(e.X + 10, e.Y - 2));
            }
            catch (Exception)
            {
                //System.Diagnostics.Debug.WriteLine("Not good move..");
            }
        }
        /// <summary>
        /// 鼠标抬起事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Wafermap_MouseUp(object sender, MouseEventArgs e)
        {
            try
            {
                List<Die> dies = new List<Die>();
                waferMappingQuadTree.SearchPoint(e.X, Height - e.Y, ref dies);
                int aa = dies.Count;
                lbMouseDown.Text = string.Format("mouse down: x={0}, y={1} have {2} count die", e.X, e.Y, dies.Count);
                if (dies.Count > 0) SelectOneDie = dies[0];
                if (OnDieClick != null && dies.Count > 0) OnDieClick(this, dies[0]);
            }
            catch (Exception)
            {
                //System.Diagnostics.Debug.WriteLine("Not good move..");
            }
        }



        // 如果鼠标指针进入格子，此方法将被调用
        private void dieEntered(Die previousDie, Die currentDie){
            if (currentDie == null) return;
            updateDie(previousDie, currentDie);
        }
        // This method should get overridden if you want to reakt on clicks on a die
        private void dieMouseDown(Die die, MouseEventArgs e) {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                MouseDownDie(die);
            }
            else
            { }
            die.MouseArgs = e;
            //if (OnDieClick != null) OnDieClick(this, die);
        }
        private void dieMouseUp(Die die, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                MouseUpDie(die);
            }
            else
            {
            }
        }

        /// <summary>
        /// 获取矩形左上角和右下角两个点
        /// </summary>
        /// <param name="startDie"></param>
        /// <param name="endDie"></param>
        /// <returns></returns>
        private Die[] GetLeftTopAndRightBottomDie(Die startDie, Die endDie)
        {
            Die[] dies = new Die[2];
            //if (endDie.XIndex >= startDie.XIndex) // end的X在start的右边
            //{
            //    if (endDie.YIndex >= startDie.YIndex) // 那么end是右下角那个点
            //    {
            //        dies[0] = startDie;
            //        dies[1] = endDie;

            //    }
            //    else // end是右上角那个点
            //    {
            //        int topLeftX = startDie.XIndex;
            //        int topLeftY = endDie.YIndex;
            //        int bottomRightX = endDie.XIndex;
            //        int bottomRightY = startDie.YIndex;
            //        dies[0] = dataset[topLeftX, topLeftY];
            //        dies[1] = dataset[bottomRightX, bottomRightY];
            //    }
            //}
            //else
            //{
            //    if (endDie.YIndex >= startDie.YIndex) // 那么end是左下角那个点
            //    {
            //        int topLeftX = endDie.XIndex;
            //        int topLeftY = startDie.YIndex;
            //        int bottomRightX = startDie.XIndex;
            //        int bottomRightY = endDie.YIndex;
            //        dies[0] = dataset[topLeftX, topLeftY];
            //        dies[1] = dataset[bottomRightX, bottomRightY];
            //    }
            //    else // end是左上角那个点
            //    {
            //        dies[0] = endDie;
            //        dies[1] = startDie;
            //    }
            //}
            return dies;
        }
        /// <summary>
        /// 实时绘制选中的dies
        /// </summary>
        private void DrawSelectDies()
        {
            if (!_SelectMultiple) return;
            if (_selectEndDie == null || _selectStartDie == null) return;
            if (_selectStartDie.XIndex == _selectEndDie.XIndex && _selectStartDie.YIndex == _selectEndDie.YIndex) { _SelectDies = null;return; }


            //Die[] dies = GetLeftTopAndRightBottomDie(_selectStartDie, _selectEndDie);
            //_SelectRegionDiagonalDie = dies;
            //if (dies.Length < 2) return;
            //if (_SelectDies != null) _SelectDies.Clear();
            //_SelectDies = new List<Die>();
            //for (int x = dies[0].XIndex; x <= dies[1].XIndex; x++)
            //{
            //    for (int y = dies[0].YIndex; y <= dies[1].YIndex; y++)
            //    {
            //        _SelectDies.Add(dataset[x, y]);
            //    }
            //}
            Invalidate();
        }

        Pen dieMoveingPen = new Pen(Color.Black);
        // This method should be used to change die coloring of a bin directly
        // This is needed to avoid redraws when not neccessary
        // The updated bins are filled with higher alpha to highlight them
        /// <summary>
        /// 移动的时候显示
        /// </summary>
        /// <param name="previousX"></param>
        /// <param name="previousY"></param>
        /// <param name="previousBincode"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="bincode"></param>
        private void updateDie(Die previosDie, Die currentDie)
        {
            //Invalidate();
            //Color fill = Color.FromArgb(80, colors[bincode]);

            Point position = TransToLeftBottom(currentDie.GetDieRectLeftBottomPoint(true, ScaleX, ScaleY));
            position = new Point(position.X + Convert.ToInt32(boundingBox_.X), position.Y - Convert.ToInt32(boundingBox_.Y));
            RectangleF die = new RectangleF(position, currentDie.GetDieSize(ScaleX, ScaleY));

            Graphics g = this.CreateGraphics();
            // update clipping
            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox_);
            // Set clipping region to path.
            g.SetClip(clipPath, CombineMode.Replace);
            // 移动的时候也不显示不在显示范围内的
            if (currentDie.IsEdge) return;
            //Draw previous
            if (previousX != -1 && previousY != -1 && previousX != _SelectX && previousX != _SelectY) // 加了！=selectX 主要是防止已经选中的划过会出现白边框
            {
                Color previousFill = Color.FromArgb(_DieAlpha, colors[previosDie.ColorIndex]);
                PointF previousPosition = new PointF(boundingBox_.X + (float)previousX * dieSize_.Width, boundingBox_.Y + (float)previousY * dieSize_.Height);
                RectangleF pDieRect = new RectangleF(previousPosition, dieSize_);
                g.FillRectangle(new SolidBrush(previousFill), pDieRect);
                g.DrawRectangle(dieOutlinePen, pDieRect.X, pDieRect.Y, pDieRect.Width, pDieRect.Height);
                //g.DrawRectangle(dieOutlinePen, previousDie.X + 5, previousDie.Y + 5, previousDie.Width - 10, previousDie.Height - 10);
            }


            // Draw
            //g.FillRectangle(new SolidBrush(fill), die);


            // 放到for循环外主要是为了解决右边和下边的边框被重绘了造成部分白色区域
            Color fillSelect = Color.FromArgb(255, Color.Red);
            Point point = TransToLeftBottom(currentDie.GetDieRectLeftBottomPoint(true, ScaleX, ScaleY));
            point = new Point(point.X + Convert.ToInt32(boundingBox_.X) - 1, point.Y - Convert.ToInt32(boundingBox_.Y) - 1);
            Size dieSize = currentDie.GetDieSize(ScaleX, ScaleY);

            RectangleF dieSelect = new RectangleF(point, new Size(dieSize.Width + 2, dieSize.Height + 2));


            g.FillRectangle(new SolidBrush(fillSelect), dieSelect);
            // 这里是重绘选中的芯片
            g.DrawRectangle(new Pen(Color.White, 4), dieSelect.X + 2, dieSelect.Y + 2, dieSelect.Width - 4, dieSelect.Height - 4);
            g.DrawRectangle(new Pen(Color.Black, 4), dieSelect.X - 2, dieSelect.Y - 2, dieSelect.Width + 4, dieSelect.Height + 4);

            //g.DrawRectangle(dieMoveingPen, die.X, die.Y, die.Width, die.Height);
            
            Invalidate();
            //g.DrawRectangle(dieOutlinePen, die.X - 5, die.Y - 5, die.Width + 10, die.Height + 10);
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.lbWaferCenter = new YiNing.UI.Controls.DarkLabel();
            this.lbMouseDown = new YiNing.UI.Controls.DarkLabel();
            this.lbBoundboxInfo = new YiNing.UI.Controls.DarkLabel();
            this.darkSettionPanel = new YiNing.UI.Controls.DarkSectionPanel();
            this.darkLabel4 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel3 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel2 = new YiNing.UI.Controls.DarkLabel();
            this.darkLabel1 = new YiNing.UI.Controls.DarkLabel();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.darkSettionPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // lbWaferCenter
            // 
            this.lbWaferCenter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.lbWaferCenter.AutoSize = true;
            this.lbWaferCenter.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(220)))), ((int)(((byte)(220)))));
            this.lbWaferCenter.Location = new System.Drawing.Point(3, 497);
            this.lbWaferCenter.Name = "lbWaferCenter";
            this.lbWaferCenter.Size = new System.Drawing.Size(155, 12);
            this.lbWaferCenter.TabIndex = 4;
            this.lbWaferCenter.Text = "WaferCenter: x={0}, y={1}";
            this.lbWaferCenter.Visible = false;
            // 
            // lbMouseDown
            // 
            this.lbMouseDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.lbMouseDown.AutoSize = true;
            this.lbMouseDown.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(220)))), ((int)(((byte)(220)))));
            this.lbMouseDown.Location = new System.Drawing.Point(3, 478);
            this.lbMouseDown.Name = "lbMouseDown";
            this.lbMouseDown.Size = new System.Drawing.Size(149, 12);
            this.lbMouseDown.TabIndex = 3;
            this.lbMouseDown.Text = "mouse down: x={0}, y={1}";
            this.lbMouseDown.Visible = false;
            // 
            // lbBoundboxInfo
            // 
            this.lbBoundboxInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.lbBoundboxInfo.AutoSize = true;
            this.lbBoundboxInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(220)))), ((int)(((byte)(220)))));
            this.lbBoundboxInfo.Location = new System.Drawing.Point(3, 515);
            this.lbBoundboxInfo.Name = "lbBoundboxInfo";
            this.lbBoundboxInfo.Size = new System.Drawing.Size(245, 12);
            this.lbBoundboxInfo.TabIndex = 2;
            this.lbBoundboxInfo.Text = "BoundboxInfo: x={0}, y={1}, w={2}, h={3}";
            this.lbBoundboxInfo.Visible = false;
            // 
            // darkSettionPanel
            // 
            this.darkSettionPanel.Controls.Add(this.darkLabel4);
            this.darkSettionPanel.Controls.Add(this.darkLabel3);
            this.darkSettionPanel.Controls.Add(this.darkLabel2);
            this.darkSettionPanel.Location = new System.Drawing.Point(3, 3);
            this.darkSettionPanel.Name = "darkSettionPanel";
            this.darkSettionPanel.SectionHeader = "鼠标操作";
            this.darkSettionPanel.Size = new System.Drawing.Size(64, 100);
            this.darkSettionPanel.TabIndex = 1;
            this.darkSettionPanel.Visible = false;
            // 
            // darkLabel4
            // 
            this.darkLabel4.AutoSize = true;
            this.darkLabel4.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel4.ForeColor = System.Drawing.Color.Green;
            this.darkLabel4.Location = new System.Drawing.Point(4, 77);
            this.darkLabel4.Name = "darkLabel4";
            this.darkLabel4.Size = new System.Drawing.Size(53, 12);
            this.darkLabel4.TabIndex = 2;
            this.darkLabel4.Text = "右键新增";
            // 
            // darkLabel3
            // 
            this.darkLabel3.AutoSize = true;
            this.darkLabel3.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel3.ForeColor = System.Drawing.Color.Red;
            this.darkLabel3.Location = new System.Drawing.Point(4, 53);
            this.darkLabel3.Name = "darkLabel3";
            this.darkLabel3.Size = new System.Drawing.Size(53, 12);
            this.darkLabel3.TabIndex = 1;
            this.darkLabel3.Text = "中键删除";
            // 
            // darkLabel2
            // 
            this.darkLabel2.AutoSize = true;
            this.darkLabel2.BackColor = System.Drawing.Color.Transparent;
            this.darkLabel2.ForeColor = System.Drawing.Color.Chocolate;
            this.darkLabel2.Location = new System.Drawing.Point(5, 29);
            this.darkLabel2.Name = "darkLabel2";
            this.darkLabel2.Size = new System.Drawing.Size(53, 12);
            this.darkLabel2.TabIndex = 0;
            this.darkLabel2.Text = "左键选择";
            // 
            // darkLabel1
            // 
            this.darkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.darkLabel1.AutoSize = true;
            this.darkLabel1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(220)))), ((int)(((byte)(220)))));
            this.darkLabel1.Location = new System.Drawing.Point(18, 499);
            this.darkLabel1.Name = "darkLabel1";
            this.darkLabel1.Size = new System.Drawing.Size(0, 12);
            this.darkLabel1.TabIndex = 0;
            // 
            // toolTip1
            // 
            this.toolTip1.AutoPopDelay = 1000;
            this.toolTip1.InitialDelay = 500;
            this.toolTip1.ReshowDelay = 100;
            // 
            // NonstandardWafermap
            // 
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(63)))), ((int)(((byte)(65)))));
            this.Controls.Add(this.lbWaferCenter);
            this.Controls.Add(this.lbMouseDown);
            this.Controls.Add(this.lbBoundboxInfo);
            this.Controls.Add(this.darkSettionPanel);
            this.Controls.Add(this.darkLabel1);
            this.Name = "NonstandardWafermap";
            this.Size = new System.Drawing.Size(666, 537);
            this.darkSettionPanel.ResumeLayout(false);
            this.darkSettionPanel.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        /// <summary>
        /// 移动的时候显示
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="bincode"></param>
        private void updateDie(Die d)
        {
            //Color fill = Color.FromArgb(255, colors[bincode]);
            PointF position = new PointF(boundingBox_.X + (float)d.XIndex * dieSize_.Width, boundingBox_.Y + (float)d.YIndex * dieSize_.Height);
            RectangleF die = new RectangleF(position, dieSize_);
            Graphics g = this.CreateGraphics();
            // update clipping
            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox_);
            // Set clipping region to path.
            g.SetClip(clipPath, CombineMode.Replace);
            // 移动的时候也不显示不在显示范围内的
            if (d.IsEdge) return;
            // Draw
            //g.FillRectangle(new SolidBrush(fill), die);

            // 内缩白色区域，更加凸显 
            g.DrawRectangle(new Pen(Color.White, 3), die.X + 2, die.Y + 2, die.Width - 4, die.Height - 4);
            g.DrawRectangle(dieMoveingPen, die.X, die.Y, die.Width, die.Height);
            //g.DrawRectangle(dieOutlinePen, die.X - 5, die.Y - 5, die.Width + 10, die.Height + 10);
        }

        private void MouseDownDie(Die d)
        {
            if (d == null) return;
            Invalidate();
            Color fill = Color.FromArgb(255, colors[d.ColorIndex]);
            PointF position = new PointF(boundingBox_.X + (float)d.XIndex * dieSize_.Width - 2, boundingBox_.Y + (float)d.YIndex * dieSize_.Height - 2);
            RectangleF die = new RectangleF(position, new SizeF(dieSize_.Width + 4, dieSize_.Height + 4));
            Graphics g = this.CreateGraphics();
            // update clipping
            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox_);
            // Set clipping region to path.
            g.SetClip(clipPath, CombineMode.Replace);

            //PointF tesPos = new PointF(position.X - 2, position.Y - 2);
            // 点击也不会显示的时候也不显示不在显示范围内的
            //if (!g.IsVisible(tesPos.X, tesPos.Y) || !g.IsVisible(tesPos.X, tesPos.Y + dieSize_.Height) || !g.IsVisible(tesPos.X + dieSize_.Width, tesPos.Y) || !g.IsVisible(tesPos.X + dieSize_.Width, tesPos.Y + dieSize_.Height))
            //{
            //    return;
            //}

            if (d.IsEdge) return;
            // Draw
            g.FillRectangle(new SolidBrush(fill), die);
            //g.DrawRectangle(dieOutlinePen, die.X - 5, die.Y - 5, die.Width + 10, die.Height + 10);

            //g.DrawRectangle(dieMoveingPen, die.X, die.Y, die.Width, die.Height);
            Invalidate();
        }

        private void MouseUpDie(Die d)
        {
            //return;
            Color fill = Color.FromArgb(255, colors[d.ColorIndex]);
            PointF position = new PointF(boundingBox_.X + (float)d.XIndex * dieSize_.Width + 2, boundingBox_.Y + (float)d.YIndex * dieSize_.Height + 2);
            RectangleF die = new RectangleF(position, new SizeF(dieSize_.Width - 4, dieSize_.Height - 4));
            Graphics g = this.CreateGraphics();
            // update clipping
            // Create graphics path.
            GraphicsPath clipPath = new GraphicsPath();
            clipPath.AddEllipse(boundingBox_);
            // Set clipping region to path.
            g.SetClip(clipPath, CombineMode.Replace);
            // 移动的时候也不显示不在显示范围内的
            if (d.IsEdge) return;
            // Draw
            g.FillRectangle(new SolidBrush(fill), die);
            //g.DrawRectangle(dieOutlinePen, die.X - 5, die.Y - 5, die.Width + 10, die.Height + 10);

            g.DrawRectangle(dieMoveingPen, die.X, die.Y, die.Width, die.Height);
            //Invalidate();
            updateDie(d);
            if (OnDieClick != null) OnDieClick(this, d);
        }
    }
}
